package com.cskaoyan.javase.oop3._5lambda._2simplify;

/**
 * Lambda表达式的简化
 * 语法:
 * () -> {}
 * Lambda表达式能够简化的前提是：它是功能接口的子类对象，而功能接口中有且只有一个必须要实现的抽象方法！
 * 简化原则: 简化不能导致Lambda有歧视.
 *
 * 接下来分别看不同的语法结构的简化:
 * 1.()能不能简化?
 *      形参列表中的数据类型,不管写不写都是不会变的,所以为了简化,干脆就不要写了
 *      特殊的,当形参只有一个时,可以省略小括号,直接写形参的名字
 *      当然如果方法是无参的,小括号是不能省略的
 * 2.{}能不能简化?
 *      可以简化,当方法重写方法体语句只有一条时,可以省略大括号
 *      特殊的,当那一条就是返回值语句时,可以连带着省略大括号和return关键字
 *
 * 实际上,在绝大多数情况下,Lambda表达式当中的方法实现不可能一条语句写完,这时Lambda表达式的格式
 *      就不那么高端了,所以Java提供了可以把一个已经存在的方法作为Lambda表达式方法实现的语法.
 *      这就是Lambda表达式当中的"方法引用",就是把一个方法作为Lambda表达式的实现
 *      什么样的方法能够作为Lambda表达式的实现?
 *      这个已经存在的方法必须能够对的上抽象方法的实现,所以:
 *      1.返回值类型必须完全一致
 *      2.方法的名字无所谓,一样不一样都行
 *      3.形参列表必须完全一致
 *      4.方法体无所谓
 *      5.修饰符也无所谓
 *
 * 方法引用的语法:
 *      () -> 已存在的方法(形参列表);
 *
 * 注意:
 *     如果是同类中直接写方法名即可，如果不是同类，就必须要指出方法来自哪里（通过类名或对象名访问）
 *
 * 方法引用的简化,最简单的Lambda表达式形式:
 *      接口名 对象名 = 方法的归属者::方法名;
 *      方法的归属者::方法名; 就表示一个Lambda表达式
 *      方法的归属者:
 *              1.static方法属于类
 *              2.成员方法属于对象
 *
 * 以上简化,方法引用是最常见的,它没有破坏Lambda表达式的简洁美感.
 *
 * @since 17:19
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        INoReturnTwoParam ip1 = (a, b) -> {
            System.out.println("a和b的和是:" + (a + b));
        };
        ip1.test(1, 1);

        INoReturnOneParam ip2 = a -> {
            System.out.println("a的值是:" + a);
        };
        ip2.test(100);

        INoReturnNoParam ip3 = () -> System.out.println("我是高端的玩法,我是Lambda表达式!");
        ip3.test();

        IHasReturnNoParam ip4 = () -> 1;
        System.out.println(ip4.test());

        Demo d = new Demo();
        INoReturnNoParam ip5 = () -> d.myTest();
        ip5.test();

        // 方法引用中的形参必须和Lambda表达式的形参一致,表示将Lambda表达式中抽象方法的参数传给那个已经实现的方法
        IHasReturnTwoParam ip6 = (a, b) -> A.aStaticTest(a, b);
        ip6.test(100, 20);
        System.out.println("-------------");
        IHasReturnTwoParam ip7 = (a, b) -> new A().aMemberTest(a, b);
        ip7.test(200, 30);
        System.out.println("-------------");

        IHasReturnTwoParam ip8 = new A()::aMemberTest;
        IHasReturnTwoParam ip9 = A::aStaticTest;
        ip8.test(1, 1);
        System.out.println("--------------");
        ip9.test(2,2);

    }

    // 写INoReturnNoParam接口的抽象方法实现
    public void myTest() {
        System.out.println("我是方法引用中INoReturnNoParam接口的抽象方法实现!");
    }

}

class A {
    // 写IHasReturnTwoParam接口的抽象方法实现
    public int aMemberTest(int num1, int num2) {
        System.out.println("两个数的和:" + (num1 + num2));
        System.out.println("两个数的差:" + (num1 - num2));
        System.out.println("两个数的积:" + (num1 * num2));
        System.out.println("两个数的商:" + (num1 / (num2 * 1.0)));
        return 0;
    }

    // 写IHasReturnTwoParam接口的抽象方法实现
    public static int aStaticTest(int num1, int num2) {
        System.out.println("两个数的和:" + (num1 + num2));
        System.out.println("两个数的差:" + (num1 - num2));
        System.out.println("两个数的积:" + (num1 * num2));
        System.out.println("两个数的商:" + (num1 / (num2 * 1.0)));
        return 0;
    }
}

//无返回值无参数的功能接口
@FunctionalInterface
interface INoReturnNoParam {
    void test();
}

//无返回值有一个参数的功能接口
@FunctionalInterface
interface INoReturnOneParam {
    void test(int a);
}

//无返回值两个参数的功能接口
@FunctionalInterface
interface INoReturnTwoParam {
    void test(int a, int b);
}

//有返回值无参数的功能接口
@FunctionalInterface
interface IHasReturnNoParam {
    int test();
}

//有返回值一个参数的功能接口
@FunctionalInterface
interface IHasReturnOneParam {
    int method(int a);
}

//有返回值两个参数的功能接口
@FunctionalInterface
interface IHasReturnTwoParam {
    int test(int a, int b);
}